@model WalkingTec.Mvvm.Core.BaseVM
<style>
    a {
        color: #01aaed
    }
</style>

<p>BaseTemplateVM和BaseImportVM是框架中负责导入的VM，TemplateVM用来定义Excel模板，ImportVM使用TemplateVM定义的模板进行导入操作</p>
<wt:fieldset field-set-style="Simple" title="建立一个BaseImportVM">
    <p>ImportVM需要使用TemplateVM中定义的模板，所以建立ImportVM需要两个步骤</p>
    <p>1. 建立一个TemplateVM，并定义需要导入的字段</p>
    <p>2. 建立一个ImportVM，将第一步创建的TemplateVM作为泛型变量传入</p>
    <p>下面以学校的模型为例，演示如何建立一个ImportVM进行学校信息的导入。学校模型的定义可以参考<a href="/#/QuickStart/FirstModule">第一个模块</a></p>
    <wt:code title="SchoolImportVM.cs">
public class SchoolTemplateVM : BaseTemplateVM
{
    [Display(Name = "学校编码")]
    public ExcelPropety SchoolCode_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolCode);
    [Display(Name = "学校名称")]
    public ExcelPropety SchoolName_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolName);
    [Display(Name = "学校类型")]
    public ExcelPropety SchoolType_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolType);
    [Display(Name = "备注")]
    public ExcelPropety Remark_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.Remark);
}

public class SchoolImportVM : BaseImportVM&ltSchoolTemplateVM, School&gt
{

}
        </wt:code>
    <p>对于简单的导入，以上代码就足够了，只是继承基类并定义需要导入的字段，框架会完成导入工作</p>
    <wt:quote>
        ExcelPropety是框架提供的类，用来定义需要导入的列
    </wt:quote>
</wt:fieldset>
<wt:fieldset field-set-style="Simple" title="使用BaseImportVM">
    <p>在Controller中使用BaseImportVM的步骤也是一目了然，请看下面的例子</p>
    <wt:code title="SchoolController.cs">
#region 导入
[ActionDescription("导入")]
public ActionResult Import()
{
    var vm = CreateVM&ltSchoolImportVM&gt();
    return PartialView(vm);
}

[HttpPost]
[ActionDescription("导入")]
public ActionResult Import(SchoolImportVM vm, IFormCollection nouse)
{
    if (vm.ErrorListVM.EntityList.Count &gt 0 || !vm.BatchSaveData())
    {
        return PartialView(vm);
    }
    else
    {
        return FFResult()
      .RefreshGrid()
      .CloseDialog()
      .Alert("成功导入 " + vm.EntityList.Count.ToString() + " 行数据");
    }
}
#endregion
    </wt:code>
    <wt:quote>
        <p>BatchSaveData是ImportVM中定义的函数，它会进行最终的导入数据库的操作</p>
        <p>必须使用CreateVM函数来创建ViewModel，而不要直接new。CreateVM函数会将当前Controller的Session，ModelState等信息传递给VM，并进行一些框架内部的操作</p>
        <p>FFResult是框架提供的一个辅助类，主要是方便开发人员返回常用js，比如关闭当前窗口，刷新grid等</p>
    </wt:quote>
</wt:fieldset>

<wt:fieldset field-set-style="Simple" title="自定义验证">
    <p>ImportVM会根据关联的Model找到其对应的BaseCRUDVM，如果能找到，则调用BaseCRUDVM中的Validate和SetDuplicatedCheck方法来进行逻辑验证和数据重复性验证</p>
    <p>同时，ImportVM本身也可以重写SetDuplicatedCheck方法，最终框架会合并ImportVM和BaseCRUDVM中的数据重复性验证</p>
    <p>SetDuplicatedCheck的写法请参考BaseCRUDVM中的对应章节</p>
</wt:fieldset>

<wt:fieldset field-set-style="Simple" title="复杂的导入模板">
    <p>框架会根据绑定字段类型，自动生成Excel模板，比如会把枚举列自动生成下拉菜单</p>
    <p>框架也支持手动设定复杂的模板，比如导入的时候需要用下拉菜单来选择关联表数据</p>
    <p>比如前面的例子，如果学校名称必须从下拉菜单中选择，我们可以这样实现</p>
    <wt:code title="SchoolImportVM.cs">
public class SchoolTemplateVM : BaseTemplateVM
{
    [Display(Name = "学校编码")]
    public ExcelPropety SchoolCode_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolCode);
    [Display(Name = "学校名称")]
    public ExcelPropety SchoolName_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolName);
    [Display(Name = "学校类型")]
    public ExcelPropety SchoolType_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolType);
    [Display(Name = "备注")]
    public ExcelPropety Remark_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.Remark);

    protected override void InitVM()
    {
        SchoolName_Excel.DataType = ColumnDataType.ComboBox;
        SchoolName_Excel.ListItems = new List&ltComboSelectListItem&gt
        {
            new ComboSelectListItem{ Text="aaa", Value="aaa"},
            new ComboSelectListItem{ Text="bbb", Value="bbb"},
            new ComboSelectListItem{ Text="ccc", Value="ccc"},
            new ComboSelectListItem{ Text="ddd", Value="ddd"},
        };
    }
}

public class SchoolImportVM : BaseImportVM&ltSchoolTemplateVM, School&gt
{

}
    </wt:code>
    <p>如上所示，我们将SchoolName列的DataType设定为ComboBox，并指定其ListItems就可以了，框架会在生成模板的时候自动在Excel里生成下拉菜单</p>
</wt:fieldset>

<wt:fieldset field-set-style="Simple" title="自定义导入">
    <p>框架提供的默认流程有时候并不完全满足需要</p>
    <p>比如你需要对Excel上填写的数据进行加工，然后才保存到数据库</p>
    <p>下面的代码演示了通过重写BatchSaveData方法修改excel中的数据，然后再导入</p>
    <wt:code title="SchoolImportVM.cs">
public class SchoolTemplateVM : BaseTemplateVM
{
    [Display(Name = "学校编码")]
    public ExcelPropety SchoolCode_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolCode);
    [Display(Name = "学校名称")]
    public ExcelPropety SchoolName_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolName);
    [Display(Name = "学校类型")]
    public ExcelPropety SchoolType_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.SchoolType);
    [Display(Name = "备注")]
    public ExcelPropety Remark_Excel = ExcelPropety.CreateProperty&ltSchool&gt(x =&gt x.Remark);

}

public class SchoolImportVM : BaseImportVM&ltSchoolTemplateVM, School&gt
{
        public override bool BatchSaveData()
        {
            //获取excel中的数据并保存在EntityList中
            SetEntityList();
            //循环数据把学校名称后面加个X
            foreach (var item in EntityList)
            {
                item.SchoolName += "X";
            }
            //调用父类方法进行保存，如果还有特殊需求，可以自己操作DC进行数据保存
            return base.BatchSaveData();
        }
}
    </wt:code>
</wt:fieldset>


<wt:fieldset field-set-style="Simple" title="主子表导入">
    <p>框架支持主子表同时导入</p>
    <p>下面的代码演示了同时导入学校，和学校下面的专业</p>
    <wt:code title="SchoolImportVM.cs">
public class SchoolTemplateVM : BaseTemplateVM
{
    [Display(Name = "学校编码")]
    public ExcelPropety SchoolCode_Excel = ExcelPropety.CreateProperty&ltSchool&gt( x =&gt x.SchoolCode);
    [Display(Name = "学校名称")]
    public ExcelPropety SchoolName_Excel = ExcelPropety.CreateProperty&ltSchool&gt( x =&gt x.SchoolName);
    [Display(Name = "学校类型")]
    public ExcelPropety SchoolType_Excel = ExcelPropety.CreateProperty&ltSchool&gt( x =&gt x.SchoolType);
    [Display(Name = "备注")]
    public ExcelPropety Remark_Excel = ExcelPropety.CreateProperty&ltSchool&gt( x =&gt x.Remark);

    [Display(Name = "专业编码")]
    public ExcelPropety MajorCode_Excel = ExcelPropety.CreateProperty<School>( x =&gt x.Majors[0].MajorCode);
    [Display(Name = "专业名称")]
    public ExcelPropety MajorName_Excel = ExcelPropety.CreateProperty<School>( x =&gt x.Majors[0].MajorName);
    [Display(Name = "专业类型")]
    public ExcelPropety MajorType_Excel = ExcelPropety.CreateProperty<School>( x =&gt x.Majors[0].MajorType);

}

public class SchoolImportVM : BaseImportVM&ltSchoolTemplateVM, School&gt
{
}
    </wt:code>
    <p>如上所示，我们在定义字段的时候，可以使用x.Majors[0].MajorCode这种写法指定他是一个子表的字段</p>
    <p>主子表导入的时候，使用下图所示的形式填写模板</p><br />
            <img src="~/imgs/Import.png" /><br /><br />

</wt:fieldset>


<wt:fieldset field-set-style="Simple" title="主要函数">
 </wt:fieldset>
   <table lay-filter="parse-table-demo">
        <thead>
            <tr>
                <th lay-data="{field:'username', width:200}">函数</th>
                <th lay-data="{field:'joinTime', width:400}">描述</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>GenerateTemplate()</td>
                <td>生成模板</td>
            </tr>
            <tr>
                <td>SetEntityList</td>
                <td>将模板数据保存到本地类中，如果默认逻辑不能支持需求，可以在子类中重写此函数</td>
            </tr>
            <tr>
                <td>BatchSaveData</td>
                <td>进行最终的数据库写入操作，如果默认逻辑不能支持需求，可以在子类中重写此函数</td>
            </tr>
        </tbody>
    </table>
    <script>
    layui.use('code',function(){layui.code({ about: false })})
    </script>
    <script>
        layui.table.init('parse-table-demo', {
        limit: 100, page: false
        });
    </script>
<script>
  $("#@Model.ViewDivId").parent().css("height", "auto");
</script>
